package subcommands

import (
	"fmt"
	"rc/logger"
	"rc/repo/model"

	"rc/repo"

	flags "github.com/jessevdk/go-flags"
	"github.com/urfave/cli"
)

func ListCli(c *cli.Context) error {
	var err error
	var nodes = make([]model.Node, 0)
	var groupNames = make([]string, 0)

	nodes, groupNames, err = getListGroupsAndNodes(c.StringSlice("g"), c.StringSlice("n"))

	displayListResult(nodes, groupNames, c.Bool("p"))
	return err
}

func List(args []string) error {
	var err error
	var log = logger.GetLogger()
	// opts for list subcommand
	var opts struct {
		Groups   []string `short:"g" long:"group" description:"group names"`
		Nodes    []string `short:"n" long:"node" description:"node names"`
		Password bool     `short:"p" description:"display password or not"`
	}

	log.Debug("original args: %#v\n", args)
	log.Debug("original args: %#v\n", len(args))

	var parser = flags.NewParser(&opts, flags.HelpFlag|flags.PassDoubleDash)
	parser.Command.Name = "list" // set current command name
	_, err = parser.ParseArgs(args)
	if err != nil {
		if err.(*flags.Error).Type == flags.ErrHelp {
			fmt.Println(err.Error())
			return nil
		}
		log.Debug("parser error : %#v\n", err)
		return err
	}
	log.Debug("opts: %v\n", opts)

	// get nodes by group and node names
	var nodes = make([]model.Node, 0)
	var groupNames = make([]string, 0)
	nodes, groupNames, err = getListGroupsAndNodes(opts.Groups, opts.Nodes)
	log.Debug("%v\n", nodes)
	displayListResult(nodes, groupNames, opts.Password)
	return err
}

func getListGroupsAndNodes(iGroups, iNodes []string) ([]model.Node, []string, error) {
	var log = logger.GetLogger()
	var err error
	var r = repo.GetRepo()
	if r == nil {
		return nil, nil, fmt.Errorf("may be repo is empty, default repo is : ~/.rc.json")
	}

	log.Debug("%v\n", r)

	var nodes = make([]model.Node, 0)
	var groupNames = make([]string, 0)

	var tmpNodes []model.Node
	var tmpGroupNames []string
	if len(iGroups) > 0 {
		for _, gName := range iGroups {
			if tmpNodes, tmpGroupNames, err = r.GetNodesWithGroupName("", gName); err != nil {
				return nil, nil, err
			}
			nodes = append(nodes, tmpNodes...)
			groupNames = append(groupNames, tmpGroupNames...)
		}
	}

	if len(iNodes) > 0 {
		for _, nName := range iNodes {
			if tmpNodes, tmpGroupNames, err = r.GetNodesWithGroupName(nName, ""); err != nil {
				return nil, nil, err
			}
			nodes = append(nodes, tmpNodes...)
			groupNames = append(groupNames, tmpGroupNames...)
		}
	}

	// not input -g and -n
	if len(iGroups) == 0 && len(iNodes) == 0 {
		nodes, groupNames, err = r.GetNodesWithGroupName("", "")
		if err != nil {
			return nil, nil, err
		}
	}

	return nodes, groupNames, err
}

func displayListResult(nodes []model.Node, groupNames []string, isPassword bool) {
	// delete repeat nodes
	var uniqNodes = make([]model.Node, 0)
	var filterGroupNames = make([]string, 0)

	for index, n := range nodes {
		var isUniq = true
		for _, un := range uniqNodes {
			if n.Name == un.Name && n.IPv4 == un.IPv4 && n.Port == un.Port {
				isUniq = false
				break
			}
		}
		if isUniq {
			uniqNodes = append(uniqNodes, n)
			filterGroupNames = append(filterGroupNames, groupNames[index])
		}
	}

	// display
	fmt.Printf("%-4s%-15s%-15s%-15s%-6s%s\n", "No.", "group", "node", "ipv4", "port", "userinfo(username,password/keypath)")
	fmt.Println("================================================================================")
	for i, n := range uniqNodes {
		var userInfo = getUserInfos(n, isPassword)
		fmt.Printf("%-4d%-15s%-15s%-15s%-6d%s\n", i+1, filterGroupNames[i], n.Name, n.IPv4, n.Port, userInfo)
	}
}

func getUserInfos(n model.Node, isPassword bool) string {
	var uiStr = ""
	if n.UserInfos == nil {
		return uiStr
	}

	for _, ui := range n.UserInfos {
		var userInfo = ui.UserName
		if isPassword {
			if ui.Password != "" {
				userInfo += "," + ui.Password
			} else if ui.KeyPath != "" {
				userInfo += "," + ui.KeyPath
			} else {
				// nothing
			}
		}
		if uiStr == "" {
			uiStr = userInfo
		} else {
			uiStr += "\n" + fmt.Sprintf("%55s%s", " ", userInfo)
		}
	}

	return uiStr
}
